const arr = [1,[[2,3],4],[5]];

/** 方法1 forEach遍历数组 */
function flat(arr) {
    let result = [];
    arr.forEach(item => {
        if(Array.isArray(item))
            result = result.concat(flat(item));
        else
            result.push(item);
    });
    return result;
}

/** 方法2 Array.prototype.reduce()遍历数组 */
const flat2 = (arr) => {
    return arr.reduce((prev,cur)=>{
        if(Array.isArray(cur))
            return prev.concat(flat2(cur));
        else 
            return prev.concat(cur);
    },[]);
}

/** 方法3：用栈的思想实现flat函数 */
const flat3 = (arr) => {
    const result = [];
    const stack = arr.slice();
    while(stack.length !== 0) {
        let val = stack.pop();
        if(Array.isArray(val)) {
            stack.push(...val);
        }else{
            result.unshift(val);
        }
    }
    return result;
}

/** 方法4：通过传入整数参数控制拉平层数 */
const flat4 = (arr, num = 1) => {
    return num > 0 ? arr.reduce((prev, cur) => {
        return prev.concat(Array.isArray(cur) ? flat4(cur, num) : cur);
    }, []) : arr.slice();
}

/** 方法5：使用Generator实现flat函数 */
/** 生成器是一种特殊函数，用function* 定义，配合yield使用 */
function * flat5 (arr, num) {
    if(num === undefined)
        num = 1;
    for(const item of arr) {
        if(Array.isArray(item) && num > 0)
            yield * flat5(item, num-1);
        else {
            yield item;
        }
    }
}

console.log(Array.from(flat5(arr, 2)));


/** 方法六：原型链上手写Array.prototype.flat() */
Array.prototype.myFlat = function(num = 1) {
    if(!Number(num) || Number(num) < 0)
        return this;
    let arr = this.concat();
    while(num > 0) {
        if(arr.some(item => Array.isArray(item))) 
            arr = [].concat(...arr);
        else 
            break;
        num--;
    }
    return arr;
}

/** ES6扩展运算符 */
function flatten(arr) {
    /** 只要arr数组元素中还存在数组 */
    while(arr.some(item => Array.isArray(item)))
        arr = [].concat(...arr);
    return arr;
}
